Podwójne dziedziczenie w javie

Podwójne dziedziczenie w javie
0

Piszę grę na Androida i mam klasę Bullet która jest poruszającą sie kulką-pociskiem, chce teraz mieć klasę RotateBullet któa dziedziczy z Bullet i będzie to kulka która będzie się poruszała. Chcę też aby kulki były rozróżnialne na moje i przeciwnika, więc mam klasy HeroBullet i EnemyBullet(mają na przykład inne metody służące do usuwania). No i teraz jak chcę mieć rotującą się kulkę przeciwnika to przydało by się zrobić kulkę która ma dwa dziedziczenia, no ale w javie tak nie można, ale na pewno musi być jakiś trick którego nie znam. Z góry dzięki za pomoc.
package com.example.user.bulletfalls;

Kopiuj
import android.content.Context;
import android.graphics.Point;
import android.widget.FrameLayout;

import com.example.user.bulletfalls.JsonClasses.Bullets.JsonBullet;

public abstract class Bullet extends ViewElement {
    boolean collisionAble;
    public Bullet(Context context,  int power, int speed, Point startingPoint, int width, int height, int randeringFrequency, int imageResource, FrameLayout frame,GameController controller,boolean collisionAble) {
        super(context, power, speed, startingPoint, width, height, randeringFrequency, imageResource,frame);
        this.controller=controller;
        this.collisionAble=collisionAble;

    }
    public Bullet(Context context, JsonBullet jsonBullet)
    {
        super(context,jsonBullet);
        this.collisionAble=jsonBullet.isCollisionAble();
    }


    public boolean isCollisionAble() {
        return collisionAble;
    }

    public void setCollisionAble(boolean collisionAble) {
        this.collisionAble = collisionAble;
    }

    abstract public void destroy();

    protected void move()
    {

        ((Game)this.getContext()).setX(this,(int)(getX()+speed));
        if(getX()+getWidth()>frame.getWidth()||getX()<0||getY()+getHeight()>frame.getHeight()||getY()<0)
        {
            destroy();

        }
    }





}
Kopiuj
public class RotateBulletHero extends HeroBullet {
    int rotationSpeed;
    public RotateBulletHero(Context context, int power, int speed, Point startingPoint, int width, int height, int randeringFrequency, int imageResource, FrameLayout frame, GameController controller, boolean collisionAble,int rotationSpeed) {
        super(context, power, speed, startingPoint, width, height, randeringFrequency, imageResource, frame, controller, collisionAble);
        this.rotationSpeed=rotationSpeed;
    }

    public RotateBulletHero(Context context, JsonBullet bullet) {
        super(context, bullet);
    }

    @Override
    public void move()
    {
        ((Game)this.getContext()).setX(this,(int)(getX()+speed));

        if(getX()+getWidth()>frame.getWidth()||getX()<0||getY()+getHeight()>frame.getHeight()||getY()<0)
        {
            destroy();

        }
    }
}
Kopiuj
public class HeroBullet extends Bullet {
    public HeroBullet(Context context, int power, int speed, Point startingPoint, int width, int height, int randeringFrequency, int imageResource, FrameLayout frame, GameController controller,boolean collisionAble) {
        super(context, power, speed, startingPoint, width, height, randeringFrequency, imageResource, frame, controller,collisionAble);
    }

    public HeroBullet(Context context, JsonBullet bullet) {
        super(context,bullet);
    }


    public void destroy()
    {


        controller.removeHeroBullet(this);
        ((Game)getContext()).removeObject(this);



    }

    @Override
    public ViewElement clone() {
        HeroBullet bullet= new HeroBullet(this.getContext(),this.power,this.speed,this.startingPoint,this.width,this.height,this.randeringFrequency,imageResources,this.frame,this.controller,this.collisionAble);
    return bullet;
        }
}
Kopiuj
public class EnemyBullet extends Bullet {
    public EnemyBullet(Context context, int power, int speed, Point startingPoint, int width, int height, int randeringFrequency, int imageResource, FrameLayout frame, GameController controller,boolean collisionAble) {
        super(context, power, speed, startingPoint, width, height, randeringFrequency, imageResource, frame, controller,collisionAble);
        if(speed>0)
        {
            this.speed=speed*(-1);
        }
    }

    public EnemyBullet(Context context, JsonBullet bullet) {
        super(context,bullet);
    }




    @Override
    public void destroy() {
        ((Game)getContext()).removeObject(this);
        controller.removeEnemyBullet(this);

    }

    @Override
    public ViewElement clone() {
        EnemyBullet bullet= new EnemyBullet(this.getContext(),this.power,this.speed,this.startingPoint,this.width,this.height,this.randeringFrequency,imageResources,this.frame,this.controller,this.collisionAble);
        return bullet;
    }
}
3

Podstawowy trick jest jeden. Używaj kompozycji zamiast dziedziczenia. :)

TY
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 lata
  • Postów:204
0

To, że potrzebujesz to zrobić, znaczy że masz generalnie problem z architekturą. Pytanie co zrobisz jak będzie dwóch przeciwników. Klasę Enemy1Bullet i Enemy2Bullet? A jak będzie ich 5? A jak będą się spawnować w czasie życia aplikacji?

Nie powinno być klas EnemyBullet i HeroBullet. Trzymaj je w jakimś serwisie (a nawet w repo) i zarządzaj nimi jako obiektami. Determinuj ich zależność na podstawie przynależności do obiektu, np.player.getBullet().destroy()

0

Bullet jest osobnym obiektem tworzonym przez bohatera następnie nie jest już on powiązany z bohaterem, jego poruszaniem i kolizjami z innymi obiektami zajmuje się klas Controller która przechowuje wszystkie obiekty które biorą udział w grze. Klasy HeroBulelt i Enemy Bullet różnią się od siebie usuwaniem. Jedne i drugie są w różnych tablicach, jak sprawdzam czy strzeliliłem w przeciwnika to nie muszę sprawdzać kolizji ze wszystkimi kulkami a tylko z tablicą HeroBullets

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

@Zakręcony Samiec to nadal jest zupełnie bez sensu. W ogóle cały ten kod wygląda na mocno pokręcony, mimo że robi zupełnie trywialne rzeczy. Moja rada: poćwicz podstawy zanim zaczniesz pisać gry.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
0

Dzięki za nic nie wnoszący, pesymistyczny komentarz, mam nadzieję, że ci ulżyło ;)

S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

Tyle że nie jest to pesymistyczny komentarz tylko niestety fakt. Ale to nie jest nic złego, każdy w końcu zaczynał, nie ma sensu brać się za trudniejsze rzeczy jak się nie umie prostych. Mówimy to dla Twojego dobra (i dla tych z którymi może będziesz kiedyś pracować :D )


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

@Trzeźwy Kura komentarz nie jest pesymistyczny tylko realistyczny. To co napisałeś to jest dramat, wynikający z tego że po prostu masz mało doświadczenia. Zamiast pisać strzelankę to zacznij może od gry w karty albo od planszówki? (jak już musisz grę)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
U0
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 6 lat
  • Postów:31
0

Skoro bardzo chcesz zrobić sobie krzywdę to trik się nazywa interfejsy i metody domyślne.

Sam tego chciałeś :P

TY
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 lata
  • Postów:204
0

Tak jak reszta pisze, twój kod cierpi na architekturę big bull of mud. Proponuję ci refaktoryzować go, wtedy nie będziesz potrzebował czegoś takiego jak multi-inheritance (jakby zwykłe dziedziczenie nie było dostatecznie złe)

  1. Proponuję ci, zrobić z Bulletów zwykłe pojosy (oczywiście z getterami i seterami):
Kopiuj
class Bullet {
     boolean collisionable;
     Point position;
}

oraz

Kopiuj
class RotateBullet extends Bullet{
     boolean collisionable;
     Point position;
     int rotationSpeed;
}

Zwykłe pojosy, które nie wiedzą o kontekście gry, nie decydują same o swoim cyklu życia

  1. Zrób serwis, który zarządza tymi pociskami. Napisałeś, że masz tablice (wat?!) tych pocisków i sprawdzasz kolizje między przeciwnikami.
Kopiuj
class BulletService {
    GameContext gameContext;
    Map<PlayerId, List<Bullet>> bullets;

    void create(playerId){
        bullets.putIfAbsent(playerId, new ArrayList<>());
        bullets.get(playerId).add(new Bullet());
   }

   void move(){
        bullets.values().stream().flatMap(Collection::stream).forEach(bullet -> bullet.setPosition(newPosition));
        checkCollisions();
    }

    void checkCollisions(){
        //Some collision check procedure
        collidedBullets.forEach((playerId, bullet) -> {
            gameContext.remove(bullet);
            bullets.get(playerId).remove(bullet);
        });
    }
}

Oczywiście wszystko to pseudokod.
3. Nie używaj clone'a chyba, że w androidzie jest to z jakiegoś powodu promowane
4. Staraj się nie używać rzutowanie jeśli to możliwe
5. Proponuję ci używać słowa-klucza controller w kontekście "web controllera" (mapowanie restów itp) chyba, że w androdzie jest inna konwencja
6. "collisionable", a nie "collisionAble"

Patryk27
Na marginesie: BulletService jest IMO średnią nazwą na serwis, bo rozmywa odpowiedzialność (coś w stylu BulletManager). Lepiej mieć wiele małych serwisów (BulletCollider, BulletMover itd.).
TY
Popieram =) Ja zazwyczaj mimo wszystko dodaje keyword Service na zasadze BulletMovementService czy BulletCollisionService
vpiotr
Map<PlayerId, List<Bullet>> bullets; - jak rozumiem po wystrzeleniu gracz może jeszcze różne rzeczy robić z kulami? Sterować nimi? Wywołać autodestrukcję? Jest jakiś inny cel tak mocnego związku? Bo po move() raczej widać że to bardziej szkodzi niż pomaga.
TY
Z tego co zrozumiałem OP, to asocjacja jest potrzebna, żeby było friendly-fire, czyli nie kolidować ze sobą pocisków tego samego gracza. Pytanie czy lepsza taka asocjacja, czy lepsza referencja do gracza w obiekcie Bullet
V-2
Tak naprawdę Collidable, a nie Collisionable (jakkolwiek by tego drugiego nie pisać)
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 4 godziny
  • Postów:2368
0

@Trzeźwy Kura: Może na początek da się zrobić np. BulletSpecification i produkować Bullet w oparciu o specyfikacje? Taki spec mógłby zawierać "parametry bojowe", bitmapy/animacje. Alternatywnie wzorzec Builder i produkować Bullet o dowolnej specyfikacji. Czyli miałbyś wspomnianą kompozycję zamiast dziedziczenia.

Taki spec powinien zredukować Ci ilość parametrów w konstruktorze, a logika biznesowa w Bullet mogłaby korzystać z tej specyfikacji.

Dodatkowo, wydaje mi się, że mieszasz różne rzeczy w tym Bulllet, łamiąc tym samym zasadę SRP. Dlaczego obiekt modelu ma mieć dostęp do kontrolera? :-)
Nie wydaje CI się, że to kontroler powinien reagować na naciśnięcie guzika, aktualizować model i zlecać jego renderowanie?

V-2
  • Rejestracja:prawie 8 lat
  • Ostatnio:9 miesięcy
  • Postów:671
0

Jak ci już napisano - nie modeluj zachowań za pomocą hierarchii dziedziczenia. Problem, na który się natknąłeś, najlepiej pokazuje, dlaczego to jest ślepy zaułek. Wielodziedziczenie, nawet gdyby było możliwe, to ucieczka z deszczu pod rynnę.

Szczególne rodzaje zachowania - np. wykrywania kolizji, przesuwania pocisku, usunięcia go itd. - powinny być wymodelowane jako osobne obiekty, i "wstrzyknięte" do klasy Bullet bądź do kontrolera, czy w każdym razie jakiejś klasy, która zajmuje się zarządzaniem i przeliczaniem całej sceny.

Poczytaj o wzorcach projektowych, np.:

https://pl.wikipedia.org/wiki/Strategia_(wzorzec_projektowy)
https://pl.wikibooks.org/wiki/Kody_źródłowe/Strategia_(wzorzec_projektowy)#Java

https://pl.wikipedia.org/wiki/Odwiedzaj%C4%85cy

https://pl.wikipedia.org/wiki/Obserwator_(wzorzec_projektowy)
https://pl.wikibooks.org/wiki/Kody_źródłowe/Obserwator_(wzorzec_projektowy)

To są sposoby na poskromienie pokusy wielokrotnego dziedziczenia.

Forum ewidentnie nie radzi sobie z linkami na WikiBooks, ale są one w artykułach wikipedyjnych. Generalnie i tak lepiej sięgnąć do angielskojęzycznych wersji tych materiałów.


Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem, ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia. W drugiej firmie której już pracuję mam palących marihuanę programistów [...] piszą kod "leniwie", często nie wysilając się, rozwlekając ten kod, unikając np. programowania funkcyjnego (mówię tutaj o lambdach w javie).
edytowany 3x, ostatnio: V-2
0

W końcu ktoś się zlitował i napisał wartościowy komentarz, wielkie dzięki!!! Jak skończę gierkę to wstawię linka, żeby niedowiarki nauczyły się pisać komentarze.

axelbest
Jak tak zaczynasz z programowaniem i twierdzeniem, że ludzie tutaj wypowiadający się nie potrafią pisać komentarzy - to życzę Ci powodzenia :)
0

Poczytałem trochę o tych wzorcach i jednak dalej nie rozumiem. Jedno czego nie napisałem to że ViewElement dziedziczy po ImageView, czyli ostatecznie Bullet jest reprezentacją logiczną kulki a jednocześnie graficzną. Aktywność na której jest gra odpala grę przez stworzenie controllera, controller przechowuje bohatera, listę przeciwników, i dwie listy kulek. Odpala timer, co określony cykl controller dodaje nowego wroga, wywołuje na każdym obiekcie metodę move, następnie na postaciach wywołuje shoot(), postać tworzy nową kulkę, następnie controller sprawdza kolizje, usuwa kulki i postacie (wywołując na nich destroy()) które nie mają życia i czeka na kolejny cykl timera.

  1. Jak mam używać interfejsów zamiast dziedziczenia skoro ja potrzebuję nowe atrybuty
  2. Z tym herobullet to była racja, że powinienem użyć interface,( ostatecznie zrezygnowałem z rozróżniania kulek na moje i przeciwnika w tym elemencie)
  3. Z tymi pojosami które ktoś napisał czy to ma jakiś sens w tym przypadku, kulki swoją drogą a późnij tworzenie ImageView zupełnie osobno, nie wiem dla mnie to wydaje się nie naturalne ale może tak się robi proszę o radę
    4.Clone robię po to, że w mojej klasie Hero np. mam referencję do kulki którą strzela bohater, potem klonuję ja i wypuszczam, trochę to dziwne więc jak ktoś ma lepszy pomysł to tutaj najbardziej proszę o radę
  4. W kontrolerze mam kulki i czy controller powinien je przesuwać czy tylko wywoływać klasę move()?
  5. Zgadzam się z tym że kulki nie powinny mieć kontrollera zrobiłem to bo tak było łatwiej, ale wiedziałem że to jest bzdura faktycznie trzeba to poprawić
  6. Nie rozumiem do końca o co chodzi z tą specyfikacją, jakby można było rozwinąć temat albo wysłać jakiś link do materiałów to by było super
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 4 godziny
  • Postów:2368
0
Trzeźwy Kura napisał(a):

...

  1. Nie rozumiem do końca o co chodzi z tą specyfikacją, jakby można było rozwinąć temat albo wysłać jakiś link do materiałów to by było super

Jeśli chodzi o specyfikacje, to jak dla mnie taka kulka ma charakterystyki:

  • masa
  • prędkość lotu
  • uszkodzenia
  • akcje związane z kolizjami (spowolnij bohatera, unieruchom bohatera, rykoszet od przeszkody)
  • trajektoria lotu (linia prosta, sinusoida, ... np. z malejącą amplitudą na potrzeby rzutu granatem odbijającym się od ziemi)
  • wygląd (bitmapa? link do bitmapy? )
  • min. skill bohatera żeby mógł używać tak niebezpiecznej kulki
  • itp.

Czyli różne kulki mają różną specyfikację i można taki spec różnie implementować, np.

Opcja 1) konstruktor z zamkniętą listą parametrów, które mogą się przewinąć w spec. Gdzieś tam przy inicjalizacji gry tworzysz instancje swoich specyfikacji.

Kopiuj
BulletSpec { 
	BulletSpec(int mass, int speed, int damage, ...) //
	...
}

BulletSpec specialBulllet = new BulletSpec(3,10,20,...);

Opcja 2) Jak masz dużo parametrów, to konstruktor może wyglądać koszmarnie. Wówczas możesz użyć buildera i tworzyć specyfikacje za pomocą konstrukcji jak niżej:

Kopiuj
	BulletSpec specialBullet =  BulletSpecBuilder
									.createBulletSpec()
									.setSpeed(3)
									.setMass(12)
									.setDamage(15)
									.addAction(new SlowDownHeroAction())
									.addAction(new TickleHeroAction())
									.setMinLevel(3)
									.setFlighPath(RANDOM_FLIGH_PATH)
									.build() 

Pewnie można mieć inne strategie implementacji takich specyfikacji. Istotą jest jednak, nie to jak się tworzy speca, tylko jak jest wykorzystywany.
Jak tworzysz kulkę, to podajesz jej specyfikację zgodnie z którą ma wyglądać/zachowywać się, zaś w logice wykorzystujesz dane ze specyfikacji.

Kopiuj
class Bullet { 
	
	BulletSpec spec; 			// tu mamy charakterystyki kulki , czyli **korzystamy z kompozycji**
	
	Position currentPosition; 	// bieżąca pozycja, ustawiana po wystrzeleniu kulki
	int currentTick; 			// zliczamy ticki na potrzeby aktualizacji położenia kulki 
	int power;                                // modeluje wytracanie energii z upływem czasu
	
	Bullet(BulletSpec spec) {
		...
		this.spec = spec; 
		...
	}
	
	CollisionResult collideWith(GameObject target) {
		// pseudokod - do przemyślenia jakie akcje chcesz wykonywać i jakich potrzebują argumentów
		...
		spec.getActions().forEach(executeAction(target));
		...
	}
	
	Bullet launch(Postion heroPosition) {
		...
		currentTick = 0;
		currentPosition = heroPosition;
		...
	}
	
	Position move() {
		// wywoływane co tick , korzysta ze speca, żeby określić nową pozycje zgodnie z torem lotu wynikającym ze speca 
		...
		currentPosition = calculateNewPosition()  // aktualizuje pozycje zgodnie z trajektorią wynikająca ze speca, bądź jeśli power<0, to zmienia trajektorię na swobodny spadek
		power -= spec.getCombustionRatio();
                ... 
                // inna radosna twórczość związana z ruchem
		...
	}
	
}
0

Superowo, wielkie dzięki ;)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)