Oyun içi konsol için Editline'ı nasıl kullanabilirim?


9

Oluşturduğum bir C ++ oyununa oyun içi konsol eklemek istiyorum . Konsolu oluşturmak ve iyi olduğum komutları ayrıştırmakla birlikte, metin girişi ve düzenleme yönü (örneğin, sol / sağ tuşlarını, geri alanlarını vb. Kullanma) daha ilginç şeylere harcamayı tercih ettiğim çok çaba gibi görünüyor .

Editline adında tarih ve otomatik tamamlama ile tamamlanmış konsol tarzı metin girişini işleyen bir kütüphane bulmayı başardım, ancak bunu oyunumla nasıl arayüzleyeceğinden emin değilim - özellikle tüm örnekler Standart giriş ve çıkış tutamaçlarını kullandığımı fark ettim ve readline()kendisi bir engelleme çağrısı. Kendi girişimi verebilmem ve konsolu kendi çıkışıma sunabilmem gerekiyor ve ayrıca oyun döngümün çalışmaya devam ettiğinden emin olmalıyım.

Bunu nasıl yapmalıyım?

Yanıtlar:


4

Editline kitaplığı (ve GNU readline) yalnızca terminal yetenekleriyle çalışır. Bu kütüphaneleri oyun içi konsolunuzla kullanmak için önce bir terminal öykünücüsü (TTY) uygulamanız gerekir .

Bunun yerine (bir oyun için bunu yapmak çılgınca olacağından), imleç hareketlerini uygulamanızı ve kendinizi düzenlemenizi tavsiye ederim. Bir keresinde, bunu tam olarak bu amaç için kendi oyun konsolumda işlemek için bir C ++ sınıfı yazdım. Sınıf uygun şekilde EditLine olarak adlandırılır. Sınıf temel imleç hareketlerini, ileri / geri karakter / sözcük / satır silmeleri ve geçmişi işler. Hiçbir şey fantezi, ama yararlı bulabilirsiniz. Belgeler seyrek veya yok, umarım anlayabilirsiniz. Maalesef otomatik tamamlama yok. Bunu bu sınıfı kullanarak bir üst katmana uyguladım.

editline.h

#include <string>
#include <vector>

class EditLine {
public:
    EditLine();
    EditLine(const EditLine&);

    ~EditLine();

    // assignment operator
    EditLine& operator=(const EditLine&);

    // comparison operators
    bool operator==(const EditLine&) const;
    bool operator!=(const EditLine&) const;

    // edit commands
    void accept_line();
    void reject_line();
    void insert_char(int);
    void delete_char();
    void backward_delete_char();
    void delete_word();
    void backward_delete_word();
    void delete_line();

    // motion commands
    void beginning_of_line();
    void end_of_line();
    void forward_char();
    void backward_char();
    void forward_word();
    void backward_word();

    // history commands
    void next_history();
    void previous_history();

    // accessors
    int history_pos() const;
    inline size_t history_size() const;
    inline bool empty() const;
    inline const std::string& line() const;
    inline size_t length() const;
    inline const std::string::size_type& cursor_pos() const;

    // mutators
    void set_line(const std::string& s);
    void set_cursor_pos(std::string::size_type);
    void reset_line();

private:
    std::string line_;
    std::string::size_type cursor_pos_;
    std::vector< std::string > history_;
    std::vector< std::string >::iterator last_iter_;
};

inline size_t EditLine::history_size() const { return history_.size(); }
inline const std::string& EditLine::line() const { return line_; }
inline const std::string::size_type& EditLine::cursor_pos() const { return cursor_pos_; }
inline bool EditLine::empty() const { return line_.empty(); }
inline size_t EditLine::length() const { return line_.length(); }

editline.cpp

#include "editline.h"
#include "string_utils.h"
#include <string>

namespace {
    const std::string word_delims = " !@#$%^&*()+-={}[]:\"|;'\\<>?,./";
} // namespace

EditLine::EditLine()
    : line_(std::string()),
      cursor_pos_(0),
      last_iter_(history_.end())
{

}

EditLine::EditLine(const EditLine& rhs)
{
    *this = rhs;
}

EditLine::~EditLine()
{

}

EditLine& EditLine::operator=(const EditLine& rhs)
{
    line_ = rhs.line_;
    cursor_pos_ = rhs.cursor_pos_;
    history_ = rhs.history_;
    if (rhs.last_iter_ == rhs.history_.end())
        last_iter_ = history_.end();
    else {
        last_iter_ = history_.begin();
        std::advance(last_iter_, rhs.last_iter_ - rhs.history_.begin());
    }
    return *this;
}

void EditLine::set_line(const std::string& s)
{
    line_ = s;
    cursor_pos_ = line_.size();
}

void EditLine::set_cursor_pos(std::string::size_type pos)
{
    if (pos > line_.size())
        pos = line_.size();
    cursor_pos_ = pos;
}

void EditLine::reset_line()
{
    line_.clear();
    cursor_pos_ = 0;
}

bool EditLine::operator==(const EditLine& rhs) const
{
    return (line_         == rhs.line_       &&
            cursor_pos_   == rhs.cursor_pos_ &&
            history_      == rhs.history_    &&
            history_pos() == rhs.history_pos());
}

bool EditLine::operator!=(const EditLine& rhs) const
{
    return !operator==(rhs);
}

void EditLine::accept_line()
{
    if (!line_.empty())
        history_.push_back(line_);

    line_.clear();
    cursor_pos_ = 0;
    last_iter_ = history_.end();
}

void EditLine::reject_line()
{
    line_.clear();
    cursor_pos_ = 0;
    last_iter_ = history_.end();
}

void EditLine::insert_char(int c)
{
    line_.insert(cursor_pos_, 1, c);
    cursor_pos_++;
}

void EditLine::delete_char()
{
    line_.erase(cursor_pos_, 1);
}

void EditLine::backward_delete_char()
{
    if (cursor_pos_ > 0) {
        line_.erase(cursor_pos_ - 1, 1);
        cursor_pos_--;
    }
}

void EditLine::delete_word()
{
    std::string::size_type pos;

    // check if cursor points on a word delim
    if (word_delims.find(line_[cursor_pos_]) != std::string::npos) {
        // cursor points on a word delim - remove everything from here to
        // right up to first delim after this word.
        pos = line_.find_first_not_of(word_delims, cursor_pos_+1);
        if (pos != std::string::npos)
            pos = line_.find_first_of(word_delims, pos+1);
    } else {
        // cursor is in the middle of a word - remove everything up to first
        // delim.
        pos = line_.find_first_of(word_delims, cursor_pos_+1);
    }

    if (pos != std::string::npos)
        // removes everything right of cursor up to 'pos'
        line_.replace(cursor_pos_, pos - cursor_pos_, "");
    else
        // removes everthing right of cursor
        line_.erase(cursor_pos_);
}

void EditLine::backward_delete_word()
{
    std::string::size_type pos;

    if (cursor_pos_ == 0) return;

    // check if char left of cursor is a word delim
    if (word_delims.find(line_[cursor_pos_-1]) != std::string::npos) {
        // left of cursor is a word delim - remove everything from left of
        // cursor up to next word delim before current word.
        pos = rfind_first_not_of(line_, word_delims, cursor_pos_-1);
        if (pos != std::string::npos)
            pos = rfind_first_of(line_, word_delims, pos);
    } else {
        // left of cursor is not a word delim - remove everything left of
        // cursor up to next word delim.
        pos = rfind_first_of(line_, word_delims, cursor_pos_-1);
    }

    if (pos != std::string::npos) {
        // removes from right of pos and up to cursor
        line_.erase(pos + 1, cursor_pos_ - pos - 1);
        cursor_pos_ = pos + 1;
    } else {
        // removes everything from beginning up to cursor
        line_.erase(0, cursor_pos_);
        cursor_pos_ = 0;
    }
}

void EditLine::delete_line()
{
    line_.erase(cursor_pos_);
    cursor_pos_ = line_.size();
}

void EditLine::beginning_of_line()
{
    cursor_pos_ = 0;
}

void EditLine::end_of_line()
{
    cursor_pos_ = line_.size();
}

void EditLine::forward_char()
{
    if (cursor_pos_ < line_.size())
        cursor_pos_++;
}

void EditLine::backward_char()
{
    if (cursor_pos_ > 0)
        cursor_pos_--;
}

void EditLine::forward_word()
{
    std::string::size_type pos;

    pos = line_.find_first_of(word_delims, cursor_pos_);

    if (pos != std::string::npos)
        cursor_pos_ = pos + 1;
    else
        cursor_pos_ = line_.size();
}

void EditLine::backward_word()
{
    if (cursor_pos_ <= 1) {
        cursor_pos_ = 0;
        return;
    }

    std::string::size_type pos, cursor_pos;

    cursor_pos = cursor_pos_;

    if (cursor_pos >= 2)
        cursor_pos -= 2;

    bool found = false;

    for (int i = (int) cursor_pos; i >= 0; --i) {
        if (word_delims.find(line_[i]) != std::string::npos) {
            pos = (std::string::size_type) i;
            found = true;
            break;
        }
    }

    if (found)
        cursor_pos_ = pos + 1;
    else
        cursor_pos_ = 0;
}

void EditLine::next_history()
{
    if (!history_.empty()) {
        if (last_iter_ == history_.end() || ++last_iter_ == history_.end())
            last_iter_ = history_.begin();
        line_ = *last_iter_;
        cursor_pos_ = line_.size();
    }
}

void EditLine::previous_history()
{
    if (!history_.empty()) {
        if (last_iter_ != history_.begin())
            --last_iter_;
        else
            last_iter_ = --history_.end();

        line_ = *last_iter_;
        cursor_pos_ = line_.size();
    }
}

int EditLine::history_pos() const
{
    if (last_iter_ == history_.end())
        return -1;
    return last_iter_ - history_.begin();
}

string_utils.h

std::string::size_type rfind_first_not_of(const std::string& s,
                                          const std::string& delims,
                                          std::string::size_type pos);

std::string::size_type rfind_first_of(const std::string& s,
                                      const std::string& delims,
                                      std::string::size_type pos);

string_utils.cpp

std::string::size_type rfind_first_not_of(const std::string& s,
        const std::string& delims, std::string::size_type pos)
{
    std::string::size_type p = pos;
    while (delims.find(s[p]) != std::string::npos) {
        if (p == 0) // not found
            return std::string::npos;
        --p;
    }
    return p;
}

std::string::size_type rfind_first_of(const std::string& s,
        const std::string& delims, std::string::size_type pos)
{
    std::string::size_type p = pos;
    while (delims.find(s[p]) == std::string::npos) {
        if (p == 0) // not found
            return std::string::npos;
        --p;
    }
    return p;
}

0

Çok fazla sorun gibi görünmüyor. Bilmeniz gereken ilk şey, standart giriş ve standart çıkışın sadece akışlar olmasıdır - gerekirse kendi kendinizle değiştirilebilir. Bu konuda SO ile ilgili bir soru vardı ve AFAIK, Editline koduna girmenin ve akışlarınızı kullanması için değiştirmenin ya da kullanmanın tek iki yolu var - cin.rdbuf()ve cout.rdbuf()bunlar standart kütüphane tarafından sağlanıyor ve belgeler burada bulunabilir . Şahsen, ikincisini kullanmanızı tavsiye ederim - hack değil ve sadece oyununuza 2 satır kod eklemeyi içerir.


Bunun dışında libedit ncurses'a bağlıdır ve altında tam bir terminal (TTY) uygulaması gerektirir ...
Oskar N.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.